package com.fasterxml.jackson.core;

import java.io.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

import com.fasterxml.jackson.core.JsonParser.NumberType;
import com.fasterxml.jackson.core.exc.StreamWriteException;
import com.fasterxml.jackson.core.io.CharacterEscapes;
import com.fasterxml.jackson.core.type.WritableTypeId;
import com.fasterxml.jackson.core.type.WritableTypeId.Inclusion;
import com.fasterxml.jackson.core.util.JacksonFeatureSet;
import com.fasterxml.jackson.core.util.VersionUtil;

import static com.fasterxml.jackson.core.JsonTokenId.*;

/**
 * 添加了方法
 * <code>
 * public abstract void writeEnum(Enum<?> enumValue) throws IOException;
 * <p>
 * public void writeEnumField(String fieldName,Enum<?> enumValue) throws IOException
 * </code>
 */
public abstract class JsonGenerator implements Closeable, Flushable, Versioned {
    protected final static JacksonFeatureSet<StreamWriteCapability> DEFAULT_WRITE_CAPABILITIES = JacksonFeatureSet.fromDefaults(StreamWriteCapability.values());
    protected final static JacksonFeatureSet<StreamWriteCapability> DEFAULT_TEXTUAL_WRITE_CAPABILITIES = DEFAULT_WRITE_CAPABILITIES.with(StreamWriteCapability.CAN_WRITE_FORMATTED_NUMBERS);
    protected final static JacksonFeatureSet<StreamWriteCapability> DEFAULT_BINARY_WRITE_CAPABILITIES = DEFAULT_WRITE_CAPABILITIES.with(StreamWriteCapability.CAN_WRITE_BINARY_NATIVELY);

    public enum Feature {
        AUTO_CLOSE_TARGET(true),
        AUTO_CLOSE_JSON_CONTENT(true),
        FLUSH_PASSED_TO_STREAM(true),
        @Deprecated
        QUOTE_FIELD_NAMES(true),
        @Deprecated
        QUOTE_NON_NUMERIC_NUMBERS(true),
        @Deprecated
        ESCAPE_NON_ASCII(false),
        @Deprecated
        WRITE_NUMBERS_AS_STRINGS(false),
        WRITE_BIGDECIMAL_AS_PLAIN(false),
        STRICT_DUPLICATE_DETECTION(false),
        IGNORE_UNKNOWN(false),
        @Deprecated
        USE_FAST_DOUBLE_WRITER(false),
        @Deprecated
        WRITE_HEX_UPPER_CASE(true),
        ESCAPE_FORWARD_SLASHES(false);

        private final boolean _defaultState;
        private final int _mask;

        public static int collectDefaults() {
            int flags = 0;
            for (Feature f : values()) {
                if (f.enabledByDefault()) {
                    flags |= f.getMask();
                }
            }
            return flags;
        }

        Feature(boolean defaultState) {
            _defaultState = defaultState;
            _mask = (1 << ordinal());
        }

        public boolean enabledByDefault() {
            return _defaultState;
        }

        public boolean enabledIn(int flags) {
            return (flags & _mask) != 0;
        }

        public int getMask() {
            return _mask;
        }
    }

    protected PrettyPrinter _cfgPrettyPrinter;

    protected JsonGenerator() {
    }

    public abstract JsonGenerator setCodec(ObjectCodec oc);

    public abstract ObjectCodec getCodec();

    public StreamWriteConstraints streamWriteConstraints() {
        return StreamWriteConstraints.defaults();
    }

    @Override
    public abstract Version version();

    public abstract JsonStreamContext getOutputContext();

    public Object getOutputTarget() {
        return null;
    }

    public Object currentValue() {
        JsonStreamContext ctxt = getOutputContext();
        return (ctxt == null) ? null : ctxt.getCurrentValue();
    }

    public void assignCurrentValue(Object v) {
        JsonStreamContext ctxt = getOutputContext();
        if (ctxt != null) {
            ctxt.setCurrentValue(v);
        }
    }

    @Deprecated
    public Object getCurrentValue() {
        return currentValue();
    }

    @Deprecated
    public void setCurrentValue(Object v) {
        assignCurrentValue(v);
    }

    public abstract JsonGenerator enable(Feature f);

    public abstract JsonGenerator disable(Feature f);

    public final JsonGenerator configure(Feature f, boolean state) {
        if (state) enable(f);
        else disable(f);
        return this;
    }

    public abstract boolean isEnabled(Feature f);

    public boolean isEnabled(StreamWriteFeature f) {
        return isEnabled(f.mappedFeature());
    }

    public abstract int getFeatureMask();

    @Deprecated
    public abstract JsonGenerator setFeatureMask(int values);

    public JsonGenerator overrideStdFeatures(int values, int mask) {
        int oldState = getFeatureMask();
        int newState = (oldState & ~mask) | (values & mask);
        return setFeatureMask(newState);
    }

    public int getFormatFeatures() {
        return 0;
    }

    public JsonGenerator overrideFormatFeatures(int values, int mask) {
        return this;
    }

    public void setSchema(FormatSchema schema) {
        throw new UnsupportedOperationException(String.format("Generator of type %s does not support schema of type '%s'", getClass().getName(), schema.getSchemaType()));
    }

    public FormatSchema getSchema() {
        return null;
    }

    public JsonGenerator setPrettyPrinter(PrettyPrinter pp) {
        _cfgPrettyPrinter = pp;
        return this;
    }

    public PrettyPrinter getPrettyPrinter() {
        return _cfgPrettyPrinter;
    }

    public abstract JsonGenerator useDefaultPrettyPrinter();

    public JsonGenerator setHighestNonEscapedChar(int charCode) {
        return this;
    }

    public int getHighestEscapedChar() {
        return 0;
    }

    public CharacterEscapes getCharacterEscapes() {
        return null;
    }

    public JsonGenerator setCharacterEscapes(CharacterEscapes esc) {
        return this;
    }

    public JsonGenerator setRootValueSeparator(SerializableString sep) {
        throw new UnsupportedOperationException();
    }

    public int getOutputBuffered() {
        return -1;
    }

    public boolean canUseSchema(FormatSchema schema) {
        return false;
    }

    public boolean canWriteObjectId() {
        return false;
    }

    public boolean canWriteTypeId() {
        return false;
    }

    public boolean canWriteBinaryNatively() {
        return false;
    }

    public boolean canOmitFields() {
        return true;
    }

    public boolean canWriteFormattedNumbers() {
        return false;
    }

    public JacksonFeatureSet<StreamWriteCapability> getWriteCapabilities() {
        return DEFAULT_WRITE_CAPABILITIES;
    }

    public abstract void writeStartArray() throws IOException;

    @Deprecated
    public void writeStartArray(int size) throws IOException {
        writeStartArray();
    }

    public void writeStartArray(Object forValue) throws IOException {
        writeStartArray();
        setCurrentValue(forValue);
    }

    public void writeStartArray(Object forValue, int size) throws IOException {
        writeStartArray(size);
        setCurrentValue(forValue);
    }

    public abstract void writeEndArray() throws IOException;

    public abstract void writeStartObject() throws IOException;

    public void writeStartObject(Object forValue) throws IOException {
        writeStartObject();
        setCurrentValue(forValue);
    }

    public void writeStartObject(Object forValue, int size) throws IOException {
        writeStartObject(forValue);
    }

    public abstract void writeEndObject() throws IOException;

    public abstract void writeFieldName(String name) throws IOException;

    public abstract void writeFieldName(SerializableString name) throws IOException;

    public void writeFieldId(long id) throws IOException {
        writeFieldName(Long.toString(id));
    }

    public void writeArray(int[] array, int offset, int length) throws IOException {
        if (array == null) {
            throw new IllegalArgumentException("null array");
        }
        _verifyOffsets(array.length, offset, length);
        writeStartArray(array, length);
        for (int i = offset, end = offset + length; i < end; ++i) {
            writeNumber(array[i]);
        }
        writeEndArray();
    }

    public void writeArray(long[] array, int offset, int length) throws IOException {
        if (array == null) {
            throw new IllegalArgumentException("null array");
        }
        _verifyOffsets(array.length, offset, length);
        writeStartArray(array, length);
        for (int i = offset, end = offset + length; i < end; ++i) {
            writeNumber(array[i]);
        }
        writeEndArray();
    }

    public void writeArray(double[] array, int offset, int length) throws IOException {
        if (array == null) {
            throw new IllegalArgumentException("null array");
        }
        _verifyOffsets(array.length, offset, length);
        writeStartArray(array, length);
        for (int i = offset, end = offset + length; i < end; ++i) {
            writeNumber(array[i]);
        }
        writeEndArray();
    }

    public void writeArray(String[] array, int offset, int length) throws IOException {
        if (array == null) {
            throw new IllegalArgumentException("null array");
        }
        _verifyOffsets(array.length, offset, length);
        writeStartArray(array, length);
        for (int i = offset, end = offset + length; i < end; ++i) {
            writeString(array[i]);
        }
        writeEndArray();
    }

    public abstract void writeString(String text) throws IOException;

    public void writeString(Reader reader, int len) throws IOException {
        _reportUnsupportedOperation();
    }

    public abstract void writeString(char[] buffer, int offset, int len) throws IOException;

    public abstract void writeString(SerializableString text) throws IOException;

    public abstract void writeRawUTF8String(byte[] buffer, int offset, int len) throws IOException;

    public abstract void writeUTF8String(byte[] buffer, int offset, int len) throws IOException;

    public abstract void writeRaw(String text) throws IOException;

    public abstract void writeRaw(String text, int offset, int len) throws IOException;

    public abstract void writeRaw(char[] text, int offset, int len) throws IOException;

    public abstract void writeRaw(char c) throws IOException;

    public void writeRaw(SerializableString raw) throws IOException {
        writeRaw(raw.getValue());
    }

    public abstract void writeRawValue(String text) throws IOException;

    public abstract void writeRawValue(String text, int offset, int len) throws IOException;

    public abstract void writeRawValue(char[] text, int offset, int len) throws IOException;

    public void writeRawValue(SerializableString raw) throws IOException {
        writeRawValue(raw.getValue());
    }

    public abstract void writeBinary(Base64Variant bv, byte[] data, int offset, int len) throws IOException;

    public void writeBinary(byte[] data, int offset, int len) throws IOException {
        writeBinary(Base64Variants.getDefaultVariant(), data, offset, len);
    }

    public void writeBinary(byte[] data) throws IOException {
        writeBinary(Base64Variants.getDefaultVariant(), data, 0, data.length);
    }

    public int writeBinary(InputStream data, int dataLength) throws IOException {
        return writeBinary(Base64Variants.getDefaultVariant(), data, dataLength);
    }

    public abstract int writeBinary(Base64Variant bv, InputStream data, int dataLength) throws IOException;

    public void writeNumber(short v) throws IOException {
        writeNumber((int) v);
    }

    public abstract void writeNumber(int v) throws IOException;

    public abstract void writeNumber(long v) throws IOException;

    public abstract void writeNumber(BigInteger v) throws IOException;

    public abstract void writeNumber(double v) throws IOException;

    public abstract void writeNumber(float v) throws IOException;

    public abstract void writeNumber(BigDecimal v) throws IOException;

    public abstract void writeNumber(String encodedValue) throws IOException;

    public void writeNumber(char[] encodedValueBuffer, int offset, int len) throws IOException {
        writeNumber(new String(encodedValueBuffer, offset, len));
    }

    public abstract void writeBoolean(boolean state) throws IOException;

    public abstract void writeNull() throws IOException;

    public void writeEmbeddedObject(Object object) throws IOException {
        if (object == null) {
            writeNull();
            return;
        }

        if (object instanceof byte[]) {
            writeBinary((byte[]) object);
            return;
        }
        throw new JsonGenerationException("No native support for writing embedded objects of type " + object.getClass().getName(), this);
    }

    public void writeObjectId(Object id) throws IOException {
        throw new JsonGenerationException("No native support for writing Object Ids", this);
    }

    public void writeObjectRef(Object referenced) throws IOException {
        throw new JsonGenerationException("No native support for writing Object Ids", this);
    }

    public void writeTypeId(Object id) throws IOException {
        throw new JsonGenerationException("No native support for writing Type Ids", this);
    }

    public WritableTypeId writeTypePrefix(WritableTypeId typeIdDef) throws IOException {
        Object id = typeIdDef.id;

        final JsonToken valueShape = typeIdDef.valueShape;
        if (canWriteTypeId()) {
            typeIdDef.wrapperWritten = false;
            writeTypeId(id);
        } else {
            String idStr = (id instanceof String) ? (String) id : String.valueOf(id);
            typeIdDef.wrapperWritten = true;
            Inclusion incl = typeIdDef.include;
            if ((valueShape != JsonToken.START_OBJECT) && incl.requiresObjectContext()) {
                typeIdDef.include = incl = WritableTypeId.Inclusion.WRAPPER_ARRAY;
            }

            switch (incl) {
                case PARENT_PROPERTY:
                    break;
                case PAYLOAD_PROPERTY:
                    break;
                case METADATA_PROPERTY:
                    writeStartObject(typeIdDef.forValue);
                    writeStringField(typeIdDef.asProperty, idStr);
                    return typeIdDef;
                case WRAPPER_OBJECT:
                    writeStartObject();
                    writeFieldName(idStr);
                    break;
                case WRAPPER_ARRAY:
                default:
                    writeStartArray();
                    writeString(idStr);
            }
        }

        if (valueShape == JsonToken.START_OBJECT) {
            writeStartObject(typeIdDef.forValue);
        } else if (valueShape == JsonToken.START_ARRAY) {
            writeStartArray();
        }
        return typeIdDef;
    }

    public WritableTypeId writeTypeSuffix(WritableTypeId typeIdDef) throws IOException {
        final JsonToken valueShape = typeIdDef.valueShape;

        if (valueShape == JsonToken.START_OBJECT) {
            writeEndObject();
        } else if (valueShape == JsonToken.START_ARRAY) {
            writeEndArray();
        }

        if (typeIdDef.wrapperWritten) {
            switch (typeIdDef.include) {
                case WRAPPER_ARRAY:
                    writeEndArray();
                    break;
                case PARENT_PROPERTY: {
                    Object id = typeIdDef.id;
                    String idStr = (id instanceof String) ? (String) id : String.valueOf(id);
                    writeStringField(typeIdDef.asProperty, idStr);
                }
                break;
                case METADATA_PROPERTY:
                case PAYLOAD_PROPERTY:
                    break;
                case WRAPPER_OBJECT:
                default:
                    writeEndObject();
                    break;
            }
        }
        return typeIdDef;
    }

    public void writePOJO(Object pojo) throws IOException {
        writeObject(pojo);
    }

    public abstract void writeObject(Object pojo) throws IOException;

    public abstract void writeTree(TreeNode rootNode) throws IOException;

    public void writeBinaryField(String fieldName, byte[] data) throws IOException {
        writeFieldName(fieldName);
        writeBinary(data);
    }

    public void writeBooleanField(String fieldName, boolean value) throws IOException {
        writeFieldName(fieldName);
        writeBoolean(value);
    }

    public void writeNullField(String fieldName) throws IOException {
        writeFieldName(fieldName);
        writeNull();
    }

    public void writeStringField(String fieldName, String value) throws IOException {
        writeFieldName(fieldName);
        writeString(value);
    }

    public void writeNumberField(String fieldName, short value) throws IOException {
        writeFieldName(fieldName);
        writeNumber(value);
    }

    public void writeNumberField(String fieldName, int value) throws IOException {
        writeFieldName(fieldName);
        writeNumber(value);
    }

    public void writeNumberField(String fieldName, long value) throws IOException {
        writeFieldName(fieldName);
        writeNumber(value);
    }

    public void writeNumberField(String fieldName, BigInteger value) throws IOException {
        writeFieldName(fieldName);
        writeNumber(value);
    }

    public void writeNumberField(String fieldName, float value) throws IOException {
        writeFieldName(fieldName);
        writeNumber(value);
    }

    public void writeNumberField(String fieldName, double value) throws IOException {
        writeFieldName(fieldName);
        writeNumber(value);
    }

    public void writeNumberField(String fieldName, BigDecimal value) throws IOException {
        writeFieldName(fieldName);
        writeNumber(value);
    }

    public void writeArrayFieldStart(String fieldName) throws IOException {
        writeFieldName(fieldName);
        writeStartArray();
    }

    public void writeObjectFieldStart(String fieldName) throws IOException {
        writeFieldName(fieldName);
        writeStartObject();
    }

    public void writePOJOField(String fieldName, Object pojo) throws IOException {
        writeObjectField(fieldName, pojo);
    }

    public void writeObjectField(String fieldName, Object pojo) throws IOException {
        writeFieldName(fieldName);
        writeObject(pojo);
    }

    public abstract void writeEnum(Enum<?> enumValue) throws IOException;

    public void writeEnumField(String fieldName, Enum<?> enumValue) throws IOException {
        writeFieldName(fieldName);
        writeEnum(enumValue);
    }

    public void writeOmittedField(String fieldName) throws IOException {
    }

    public void copyCurrentEvent(JsonParser p) throws IOException {
        JsonToken t = p.currentToken();
        final int token = (t == null) ? ID_NOT_AVAILABLE : t.id();
        switch (token) {
            case ID_NOT_AVAILABLE:
                throw _constructWriteException("No current event to copy");
            case ID_START_OBJECT:
                writeStartObject();
                break;
            case ID_END_OBJECT:
                writeEndObject();
                break;
            case ID_START_ARRAY:
                writeStartArray();
                break;
            case ID_END_ARRAY:
                writeEndArray();
                break;
            case ID_FIELD_NAME:
                writeFieldName(p.currentName());
                break;
            case ID_STRING:
                _copyCurrentStringValue(p);
                break;
            case ID_NUMBER_INT:
                _copyCurrentIntValue(p);
                break;
            case ID_NUMBER_FLOAT:
                _copyCurrentFloatValue(p);
                break;
            case ID_TRUE:
                writeBoolean(true);
                break;
            case ID_FALSE:
                writeBoolean(false);
                break;
            case ID_NULL:
                writeNull();
                break;
            case ID_EMBEDDED_OBJECT:
                writeObject(p.getEmbeddedObject());
                break;
            default:
                throw new IllegalStateException("Internal error: unknown current token, " + t);
        }
    }

    public void copyCurrentEventExact(JsonParser p) throws IOException {
        JsonToken t = p.currentToken();
        final int token = (t == null) ? ID_NOT_AVAILABLE : t.id();
        switch (token) {
            case ID_NOT_AVAILABLE:
                throw _constructWriteException("No current event to copy");
            case ID_START_OBJECT:
                writeStartObject();
                break;
            case ID_END_OBJECT:
                writeEndObject();
                break;
            case ID_START_ARRAY:
                writeStartArray();
                break;
            case ID_END_ARRAY:
                writeEndArray();
                break;
            case ID_FIELD_NAME:
                writeFieldName(p.currentName());
                break;
            case ID_STRING:
                _copyCurrentStringValue(p);
                break;
            case ID_NUMBER_INT:
                _copyCurrentIntValue(p);
                break;
            case ID_NUMBER_FLOAT:
                _copyCurrentFloatValueExact(p);
                break;
            case ID_TRUE:
                writeBoolean(true);
                break;
            case ID_FALSE:
                writeBoolean(false);
                break;
            case ID_NULL:
                writeNull();
                break;
            case ID_EMBEDDED_OBJECT:
                writeObject(p.getEmbeddedObject());
                break;
            default:
                throw new IllegalStateException("Internal error: unknown current token, " + t);
        }
    }

    public void copyCurrentStructure(JsonParser p) throws IOException {
        JsonToken t = p.currentToken();

        int id = (t == null) ? ID_NOT_AVAILABLE : t.id();
        if (id == ID_FIELD_NAME) {
            writeFieldName(p.currentName());
            t = p.nextToken();
            id = (t == null) ? ID_NOT_AVAILABLE : t.id();
        }
        switch (id) {
            case ID_START_OBJECT:
                writeStartObject();
                _copyCurrentContents(p);
                return;
            case ID_START_ARRAY:
                writeStartArray();
                _copyCurrentContents(p);
                return;
            default:
                copyCurrentEvent(p);
        }
    }

    protected void _copyCurrentContents(JsonParser p) throws IOException {
        int depth = 1;
        JsonToken t;

        while ((t = p.nextToken()) != null) {
            switch (t.id()) {
                case ID_FIELD_NAME:
                    writeFieldName(p.currentName());
                    break;
                case ID_START_ARRAY:
                    writeStartArray();
                    ++depth;
                    break;
                case ID_START_OBJECT:
                    writeStartObject();
                    ++depth;
                    break;
                case ID_END_ARRAY:
                    writeEndArray();
                    if (--depth == 0) {
                        return;
                    }
                    break;
                case ID_END_OBJECT:
                    writeEndObject();
                    if (--depth == 0) {
                        return;
                    }
                    break;
                case ID_STRING:
                    _copyCurrentStringValue(p);
                    break;
                case ID_NUMBER_INT:
                    _copyCurrentIntValue(p);
                    break;
                case ID_NUMBER_FLOAT:
                    _copyCurrentFloatValue(p);
                    break;
                case ID_TRUE:
                    writeBoolean(true);
                    break;
                case ID_FALSE:
                    writeBoolean(false);
                    break;
                case ID_NULL:
                    writeNull();
                    break;
                case ID_EMBEDDED_OBJECT:
                    writeObject(p.getEmbeddedObject());
                    break;
                default:
                    throw new IllegalStateException("Internal error: unknown current token, " + t);
            }
        }
    }

    protected void _copyCurrentFloatValue(JsonParser p) throws IOException {
        NumberType t = p.getNumberType();
        if (t == NumberType.BIG_DECIMAL) {
            writeNumber(p.getDecimalValue());
        } else if (t == NumberType.FLOAT) {
            writeNumber(p.getFloatValue());
        } else {
            writeNumber(p.getDoubleValue());
        }
    }

    protected void _copyCurrentFloatValueExact(JsonParser p) throws IOException {
        Number n = p.getNumberValueExact();
        if (n instanceof BigDecimal) {
            writeNumber((BigDecimal) n);
        } else if (n instanceof Double) {
            writeNumber(n.doubleValue());
        } else {
            writeNumber(n.floatValue());
        }
    }

    protected void _copyCurrentIntValue(JsonParser p) throws IOException {
        NumberType n = p.getNumberType();
        if (n == NumberType.INT) {
            writeNumber(p.getIntValue());
        } else if (n == NumberType.LONG) {
            writeNumber(p.getLongValue());
        } else {
            writeNumber(p.getBigIntegerValue());
        }
    }

    protected void _copyCurrentStringValue(JsonParser p) throws IOException {
        if (p.hasTextCharacters()) {
            writeString(p.getTextCharacters(), p.getTextOffset(), p.getTextLength());
        } else {
            writeString(p.getText());
        }
    }

    @Override
    public abstract void flush() throws IOException;

    public abstract boolean isClosed();

    @Override
    public abstract void close() throws IOException;

    protected void _reportError(String msg) throws JsonGenerationException {
        throw (JsonGenerationException) _constructWriteException(msg);
    }

    protected final void _throwInternal() {
        VersionUtil.throwInternal();
    }

    protected void _reportUnsupportedOperation() {
        _reportUnsupportedOperation("Operation not supported by `JsonGenerator` of type " + getClass().getName());
    }

    protected void _reportUnsupportedOperation(String msg) {
        throw new UnsupportedOperationException(msg);
    }

    protected StreamWriteException _constructWriteException(String msg) {
        return new JsonGenerationException(msg, this);
    }

    protected StreamWriteException _constructWriteException(String msg, Object arg) {
        return _constructWriteException(String.format(msg, arg));
    }

    protected StreamWriteException _constructWriteException(String msg, Object arg1, Object arg2) {
        return _constructWriteException(String.format(msg, arg1, arg2));
    }

    protected StreamWriteException _constructWriteException(String msg, Throwable t) {
        return new JsonGenerationException(msg, t, this);
    }

    protected final void _verifyOffsets(int arrayLength, int offset, int length) {
        if ((offset < 0) || (offset + length) > arrayLength) {
            throw new IllegalArgumentException(String.format("invalid argument(s) (offset=%d, length=%d) for input array of %d element", offset, length, arrayLength));
        }
    }

    protected void _writeSimpleObject(Object value) throws IOException {
        if (value == null) {
            writeNull();
            return;
        }
        if (value instanceof String) {
            writeString((String) value);
            return;
        }
        if (value instanceof Number) {
            Number n = (Number) value;
            if (n instanceof Integer) {
                writeNumber(n.intValue());
                return;
            } else if (n instanceof Long) {
                writeNumber(n.longValue());
                return;
            } else if (n instanceof Double) {
                writeNumber(n.doubleValue());
                return;
            } else if (n instanceof Float) {
                writeNumber(n.floatValue());
                return;
            } else if (n instanceof Short) {
                writeNumber(n.shortValue());
                return;
            } else if (n instanceof Byte) {
                writeNumber(n.byteValue());
                return;
            } else if (n instanceof BigInteger) {
                writeNumber((BigInteger) n);
                return;
            } else if (n instanceof BigDecimal) {
                writeNumber((BigDecimal) n);
                return;

            } else if (n instanceof AtomicInteger) {
                writeNumber(((AtomicInteger) n).get());
                return;
            } else if (n instanceof AtomicLong) {
                writeNumber(((AtomicLong) n).get());
                return;
            }
        } else if (value instanceof byte[]) {
            writeBinary((byte[]) value);
            return;
        } else if (value instanceof Boolean) {
            writeBoolean((Boolean) value);
            return;
        } else if (value instanceof AtomicBoolean) {
            writeBoolean(((AtomicBoolean) value).get());
            return;
        }
        throw new IllegalStateException("No ObjectCodec defined for the generator, can only serialize simple wrapper types (type passed " + value.getClass().getName() + ")");
    }
}
